﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Quartz;
using Quartz.Impl;

namespace Wosperry.QuartzJob
{
    public class QuartzJobService : IQuartzJobService
    {
        private static ISchedulerFactory SchedulerFactory { get; set; }
        private QuartzJobOptions Options { get; set; }

        private IScheduler Scheduler;

        /// <summary>
        /// 无参构造函数，默认给个工厂
        /// </summary>
        public QuartzJobService()
        {
            SchedulerFactory = new StdSchedulerFactory();
        }

        /// <summary>
        /// 依赖注入时，需要注册 services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
        /// </summary>
        /// <param name="schedulerFactory"></param>
        public QuartzJobService(ISchedulerFactory schedulerFactory)
        {
            SchedulerFactory = schedulerFactory;
        }

        /// <summary>
        /// 异步
        /// </summary>
        /// <typeparam name="TJob">任务类型，需要实现Quartz.IJob</typeparam>
        /// <param name="optionAction">配置</param>
        /// <param name="jobData">任务参数</param>
        /// <exception cref="Exception">部分参数不符合要求时，抛出异常</exception>
        public async Task StartAsync<TJob>(QuartzJobOptions options, Dictionary<string, string> jobData = null) where TJob : IJob
        {
            IJobDetail jobDetail;
            ITrigger trigger;

            #region Scheduler
            if (Scheduler == null)
            {
                Scheduler = await SchedulerFactory.GetScheduler();
                await Scheduler.Start();
            }
            #endregion

            #region Options

            Options = options;

            if (string.IsNullOrWhiteSpace(Options.TriggerName))
            {
                throw new Exception("触发器名称不可为空");
            }

            if (string.IsNullOrWhiteSpace(Options.JobName))
            {
                Options.JobName = typeof(TJob).Name;
            }

            if (string.IsNullOrWhiteSpace(Options.GroupName))
            {
                Options.GroupName = "Default";
            }

            #endregion

            #region 创建作业
            // builder
            var jobBuilder = JobBuilder.Create<TJob>()
                 .WithIdentity(Options.JobName, Options.GroupName);

            if (jobData?.Count > 0)
            {
                foreach (var k in jobData.Keys)
                {
                    jobBuilder = jobBuilder.UsingJobData(k, jobData[k]);
                }
            }

            jobBuilder.WithDescription(Options.Description);

            // 任务实例
            jobDetail = jobBuilder.Build();
            #endregion

            #region 创建触发器
            // builder
            var triggerBuilder = TriggerBuilder.Create()
               .WithIdentity(Options.TriggerName, Options.GroupName);

            if (Options.StartAt.HasValue)
                triggerBuilder = triggerBuilder.StartAt(Options.StartAt.Value.ToUniversalTime());
            else
                triggerBuilder = triggerBuilder.StartNow();

            if (Options.EndAt.HasValue)
                triggerBuilder = triggerBuilder.EndAt(Options.EndAt.Value.ToUniversalTime());

            // 周期
            triggerBuilder = triggerBuilder.WithSimpleSchedule(x =>
            {
                var intervalSum =
                    TimeSpan.FromHours(Options.Interval.Hours) +
                    TimeSpan.FromMinutes(Options.Interval.Minuts) +
                    TimeSpan.FromSeconds(Options.Interval.Seconds);
                x.WithInterval(intervalSum > TimeSpan.Zero ? intervalSum : TimeSpan.FromSeconds(10));

                // 循环次数
                if (Options.RepeatTimes < 0)
                    x.RepeatForever();
                else
                    x.WithRepeatCount(Options.RepeatTimes);
            });
            trigger = triggerBuilder.Build();

            #endregion

            await Scheduler.ScheduleJob(jobDetail, trigger);
        }
        public async Task StartAsync<TJob>(Action<QuartzJobOptions> optionsAction, Dictionary<string, string> jobData = null) where TJob : IJob
        {
            if (optionsAction == null)
            {
                throw new Exception($"错误：任务{typeof(TJob).Name}执行时，Options参数为空！");
            }

            var options = new QuartzJobOptions();
            optionsAction.Invoke(options);

            await StartAsync<TJob>(options, jobData);
        }

        /// <summary>
        /// 同步
        /// </summary>
        /// <typeparam name="TJob">任务类型，需要实现Quartz.IJob</typeparam>
        /// <param name="optionAction">配置</param>
        /// <param name="jobData">任务参数</param>
        public void Start<TJob>(QuartzJobOptions options, Dictionary<string, string> jobData = null) where TJob : IJob
        {
            StartAsync<TJob>(options, jobData).GetAwaiter().GetResult();
        }
        public void Start<TJob>(Action<QuartzJobOptions> optionAction, Dictionary<string, string> jobData = null) where TJob : IJob
        {
            StartAsync<TJob>(optionAction, jobData).GetAwaiter().GetResult();
        }


    }
}
